﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.IO;
using System.Net;

namespace SlaktDataReader
{
    [Serializable]
    public abstract class BookBase<T>
    {
        public Guid BookID { get; set; }
        public string Area { get; set; }
        public string EditedBy { get; set; }

        public string FileName { get; set; }
        public string Parish { get; set; }
        public string Period { get; set; }
        public string PeriodStart { get; set; }
        public string PeriodEnd { get; set; }

        public string SDCode { get; set; }
        public string Source { get; set; }
        public string UpdateDate { get; set; }
        public bool IsFinished { get; set; }
        public bool HasError { get; set; }

        public abstract BookTypes BookType { get; }

        [XmlIgnore]
        public int ItemCount { get { return Items.Count(); } }

        public abstract ObservableCollection<T> Items { get; set; }

        [XmlIgnore]
        protected BackgroundWorker bwLoad;

        protected void _init()
        {
            BookID = Guid.NewGuid();
            bwLoad = new BackgroundWorker();
            bwLoad.DoWork += new DoWorkEventHandler(bwLoad_DoWork);
            bwLoad.ProgressChanged += new ProgressChangedEventHandler(bwLoad_ProgressChanged);
            bwLoad.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwLoad_RunWorkerCompleted);
        }

        protected abstract void bwLoad_DoWork(object sender, DoWorkEventArgs e);
        protected abstract void bwLoad_ProgressChanged(object sender, ProgressChangedEventArgs e);
        protected abstract void bwLoad_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e);

        public bool ReadBook(string FileName)
        {
            this.FileName = FileName;
            return ReadBook();
        }

        public abstract void ExportBook();

        /// <summary>
        /// Extracts the Start and End period
        /// </summary>
        public void GetPeriod()
        {
            try
            {
                if (string.IsNullOrEmpty(Period))
                    return;

                string[] p = Period.Split('-');
                if (p != null)
                {
                    if (p.Length > 0)
                    {
                        PeriodStart = p[0].Trim();
                        PeriodEnd = p[1].Trim();
                    }
                }
            }
            catch { }
        }

        /// <summary>
        /// Copy Data from Book 
        /// </summary>
        /// <param name="book"></param>
        public void CopyFromBook(Book book)
        {
            if (book == null) return;
            if (book.BookType != BookType) return;

            try
            {
                this.FileName = book.FileName;
                this.EditedBy = book.Author;
                this.Period = book.Period;
                this.Source = book.Source;
                this.Parish = Globals.Locations.Single(f => f.LocationID == book.Location).LocationName;
            }
            catch { }
        }

        /// <summary>
        /// Clear book
        /// </summary>
        public void ClearBook()
        {
            this.FileName = "";
            this.EditedBy = "";
            this.Period = "";
            this.Parish = "";
            this.Source = "";
            this.Area = "";

            Items = new ObservableCollection<T>();
        }

        /// <summary>
        /// Reads a Birth Book File
        /// </summary>
        /// <returns>True if the file exists and is a filename ends with a known extention. Otherwise false</returns>
        public bool ReadBook()
        {
            if (FileName == null) return false;
            bool isRemote = Uri.IsWellFormedUriString(FileName, UriKind.RelativeOrAbsolute);
            if (File.Exists(FileName) || isRemote)
            {
                BWArgs args = new BWArgs();
                if (FileName.ToUpper().EndsWith(".TXT") || isRemote)
                {
                    if (!bwLoad.IsBusy)
                    {
                        args.FileName = this.FileName;
                        args.FileType = BWArgs.BookFileType.Text;
                        bwLoad.RunWorkerAsync(args);
                        return true;
                    }
                    return false;
                }
                else if (FileName.ToUpper().EndsWith(".XLS"))
                {
                    if (!bwLoad.IsBusy)
                    {
                        args.FileName = this.FileName;
                        args.FileType = BWArgs.BookFileType.Excel;
                        bwLoad.RunWorkerAsync(args);
                        return true;
                    }
                    return false;
                }
                else if (FileName.ToUpper().EndsWith(".XML"))
                {
                    if (!bwLoad.IsBusy)
                    {
                        args.FileName = this.FileName;
                        args.FileType = BWArgs.BookFileType.XML;
                        bwLoad.RunWorkerAsync(args);
                        return true;
                    }
                    return false;
                }
                return false;
            }
            else
            {
                return false;
            }
        }

        #region Events

        public event EventHandler ReadSuccess;
        public event EventHandler ReadFail;
        public event EventHandler ExportSuccess;
        public event EventHandler ExportFail;

        /// <summary>
        /// Read Success Event Wrapper
        /// </summary>
        protected void readSuccess()
        {
            if (ReadSuccess != null)
            {
                ReadSuccess(this, new EventArgs());
            }
        }

        /// <summary>
        /// Read fail event wrapper
        /// </summary>
        protected void readFail()
        {
            if (ReadFail != null)
            {
                ReadFail(this, new EventArgs());
            }
        }

        /// <summary>
        /// Export Success event wrapper
        /// </summary>
        protected void exportSuccess()
        {
            if (ExportSuccess != null)
            {
                ExportSuccess(this, new EventArgs());
            }
        }

        /// <summary>
        /// Export fail event wrapper
        /// </summary>
        protected void exportFail()
        {
            if (ExportFail != null)
            {
                ExportFail(this, new EventArgs());
            }
        }

        #endregion
    }

    public abstract class TextFileBase
    {
        protected Dictionary<string, int> _fields = new Dictionary<string, int>();

        

        public string FileName { get; set; }
        public char Separator { get; set; }
        public Encoding FileEncoding { get; set; }

        public int Read(string FileName)
        {
            this.FileName = FileName;
            return Read();
        }

        protected string[] DownloadBook()
        {
            string[] lines;
            try
            {
                if (Globals.BookDownloadPath == null)
                    return null;

                WebClient wc = new WebClient();


                if (!Directory.Exists(Globals.BookDownloadPath))
                {
                    Directory.CreateDirectory(Globals.BookDownloadPath);
                }

                string tmpFileName = Globals.BookDownloadPath + new Uri(FileName).AbsolutePath;
                if (tmpFileName.Contains("getText.php/"))
                {
                    tmpFileName = tmpFileName.Remove(tmpFileName.IndexOf("getText.php/"), 12);
                }
                wc.DownloadFile(FileName, tmpFileName);
                lines = File.ReadAllLines(tmpFileName, FileEncoding);
                return lines;
            }
            catch { }
            return null;
        }

        /// <summary>
        /// Parse line
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        protected int _ParseLine(string line)
        {
            string[] fields;
            if (line.Length > 0)
            {
                fields = line.Split(Separator);
                if (fields.Length >= _fields.Where(f => f.Value != -1).Count() - 1)
                {
                    _AddRecord(fields);
                    return 1;
                }
            }
            return 0;
        }

        protected abstract void _AddRecord(string[] RowFields);

        protected void _ParseHeaderInfoLine(string line)
        {
            string[] kyw = { "Reg.av:", "Antal:", "Uppdat:", "Källa:", "Info:", "Licens:", "Senast uppdaterat:" };


            // Reg.av: 
            // Antal: 
            // Uppdat: 
            // Källa: 
            // Senast uppdaterat: 

            if (string.IsNullOrEmpty(line))
                return;

            foreach (string k in kyw)
            {
                if (line.Contains(k))
                {
                    // ToDo: Write this function
                }
            }

        }

        public int Read()
        {
            int i, _LinesRead = 0;
            bool HeaderFound = false;
            string[] lines = { };
            try
            {
                if (FileName == null)
                    return 0;

                if (FileName.ToUpper().StartsWith("HTTP://") || FileName.ToUpper().StartsWith("HTTPS://") || FileName.ToUpper().StartsWith("FTP://"))
                {
                    lines = DownloadBook();
                    if (lines == null)
                        return 0;
                }
                else
                {
                    lines = File.ReadAllLines(FileName, FileEncoding);
                }
                if (lines.Length == 0)
                {
                    return 0;
                }

                for (i = 0; i < lines.Length; i++)
                {
                    if (!HeaderFound)
                    {
                        if (lines[i].ToUpper().Contains("LOPNR"))
                        {
                            HeaderFound = _ParseHeader(lines[i]);
                            continue;
                        }
                        else
                        {
                            _ParseHeaderInfoLine(lines[i]);
                            continue;
                        }
                    }
                    else
                    {
                        _LinesRead += _ParseLine(lines[i]);
                    }
                }
            }
            catch
            {
                return -1;
            }
            return _LinesRead;
        }

        /// <summary>
        /// Parse header columns
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        protected bool _ParseHeader(string line)
        {
            try
            {
                if (line.Length > 0)
                {
                    string[] row = line.Split(Separator);
                    for (int i = 0; i < row.Length; i++)
                    {
                        if (_fields.ContainsKey(row[i]))
                        {
                            _fields[row[i]] = i;
                        }
                    }

                    return true;
                }
            }
            catch
            {
            }

            return false;
        }
    }
}
